package com.znxs.zuopao_c.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.znxs.zuopao_c.common.ErrorCode;
import com.znxs.zuopao_c.domain.Request.TeamExitRequest;
import com.znxs.zuopao_c.domain.Request.TeamJoinRequest;
import com.znxs.zuopao_c.domain.Request.TeamUpdateRequest;
import com.znxs.zuopao_c.domain.Team;
import com.znxs.zuopao_c.domain.User;
import com.znxs.zuopao_c.domain.UserTeam;
import com.znxs.zuopao_c.domain.dto.TeamQuery;
import com.znxs.zuopao_c.domain.vo.TeamUserVO;
import com.znxs.zuopao_c.domain.vo.UserVO;
import com.znxs.zuopao_c.enums.TeamStatusEnum;
import com.znxs.zuopao_c.exception.BusinessException;
import com.znxs.zuopao_c.service.TeamService;
import com.znxs.zuopao_c.mapper.TeamMapper;
import com.znxs.zuopao_c.service.UserService;
import com.znxs.zuopao_c.service.UserTeamService;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author znxs
 * @description 针对表【team(队伍)】的数据库操作Service实现
 * @createDate 2023-09-24 06:03:47
 */
@Service
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team>
        implements TeamService {

    @Resource
    private UserTeamService userTeamService;

    @Resource
    private UserService userService;

    @Override
    @Transactional(rollbackFor = Exception.class) // 指定返回错误类
    public long addTeam(Team team, User loginUser) {
        // 请求参数不为空
        if (team == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 是否登录
        final Long userId;
        if (loginUser == null || loginUser.getId() < 0) {
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }
        userId = loginUser.getId();

        // 校验信息
        // 队伍人数>1 且 <20
        int maxNum = Optional.ofNullable(team.getMaxNum()).orElse(0);
        if (maxNum < 1 || maxNum > 20) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍人数不符合要求");
        }
        // 队伍标题小于20
        String teamName = team.getName();
        if (StringUtils.isBlank(teamName) || teamName.length() > 20) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍标题不符合要求");
        }
        // 描述小于512
        String teamDescription = team.getDescription();
        if (StringUtils.isBlank(teamDescription) && teamDescription.length() > 512) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍描述过长");
        }
        //  队伍状态
        Integer teamStatus = Optional.ofNullable(team.getStatus()).orElse(0);
        TeamStatusEnum status = TeamStatusEnum.getTeamStatusEnumByValue(teamStatus);
        if (status == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍状态必填");
        }
        // 如果status 是加密状态 一定要有密码，并且密码<32
        String password = team.getPassword();
        if (TeamStatusEnum.SECRET.equals(status) && (StringUtils.isBlank(password) || password.length() > 32)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "加密队伍必须创建密码，并且密码<32");
        }
        // 超时时间大于当前时间
        Date expireTime = team.getExpireTime();
        if (new Date().after(expireTime)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "超时时间大于当前时间");
        }
        // 用户创建的队伍不能超过五个
        //TODO 可能同时创建100个队伍
        QueryWrapper<Team> teamQueryWrapper = new QueryWrapper<>();
        teamQueryWrapper.eq("user_id", userId);
        long count = count(teamQueryWrapper);
        if (count >= 5) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户创建的队伍不能超过五个");
        }

        // 插入信息到队伍中  这里开启事务
        team.setId(null);
        team.setUserId(userId);
        boolean result = save(team);
        Long teamId = team.getId();
        if (!result || teamId == null) {
            throw new BusinessException(ErrorCode.SYS_ERROR, "插入队伍出错");
        }
        // 插入关系表
        UserTeam userTeam = new UserTeam();
        userTeam.setTeamId(team.getId());
        userTeam.setUserId(userId);
        userTeam.setJoinTime(new Date());
        boolean save = userTeamService.save(userTeam);
        if (!save) {
            throw new BusinessException(ErrorCode.SYS_ERROR, "插入队伍出错");
        }

        return teamId;
    }

    @Override
    public List<TeamUserVO> listTeams(TeamQuery teamQuery, Boolean isAdmin) {
        QueryWrapper<Team> teamQueryQueryWrapper = new QueryWrapper<>();
        if (teamQuery != null) {
            Long id = teamQuery.getId();
            if (id != null && id > 0) {
                teamQueryQueryWrapper.eq("id", id);
            }
            // 如果有传入listTeams 根据listTeams查询
            List<Long> idList = teamQuery.getIdList();
            if (idList!=null && !idList.isEmpty()){
                teamQueryQueryWrapper.in("id",idList);
            }
            // 可以使搜索词在名称里面查或者在描述信息里面查
            String searchText = teamQuery.getSearchText();
            if (StringUtils.isNotBlank(searchText)) {
                teamQueryQueryWrapper.and(qw -> qw.like("name", searchText).or().like("description", searchText));
            }
            // 根据队伍名称查询
            String name = teamQuery.getName();
            if (StringUtils.isNotBlank(name)) {
                teamQueryQueryWrapper.like("name", name);
            }
            // 根据队伍描述信息查询
            String description = teamQuery.getDescription();
            if (StringUtils.isNotBlank(description)) {
                teamQueryQueryWrapper.like("description", description);
            }
            // 根据队伍最大人数查询
            Integer maxNum = teamQuery.getMaxNum();
            if (maxNum != null && (maxNum > 1 && maxNum < 20)) {
                teamQueryQueryWrapper.eq("max_num", maxNum);
            }
            // 根据创建人的id查询
            Long userId = teamQuery.getUserId();
            if (userId != null && userId > 0) {
                teamQueryQueryWrapper.eq("user_id", userId);
            }
            // 根据队伍状态查询
            Integer status = teamQuery.getStatus();
            // 如果不是管理员 就不能查询所有的非公开的队伍
            TeamStatusEnum teamStatusValue = TeamStatusEnum.getTeamStatusEnumByValue(status);
            // 如果队伍没有状态就设定为公开
            if (teamStatusValue == null) teamStatusValue = TeamStatusEnum.PUBLIC;
            if (!isAdmin && !TeamStatusEnum.PUBLIC.equals(teamStatusValue)) {
                throw new BusinessException(ErrorCode.NO_AUTH, "非管理员无权限查看非公开队伍");
            }
            // 添加根据状态查询条件
            teamQueryQueryWrapper.eq("status", teamStatusValue.getValue());

            // 不展示过期的队伍
            // teamQueryQueryWrapper.gt("expire_time", new Date()).or().isNotNull("expire_time");
        }



        // 查询对应的队伍列表
        List<Team> teamList = list(teamQueryQueryWrapper);
        if (CollectionUtils.isEmpty(teamList)) {
            return new ArrayList<>();
        }
        ArrayList<TeamUserVO> userVOList = new ArrayList<>();
        // 关联查询用户信息
        // 遍历每个队伍
        for (Team team : teamList) {
            // 不展示过期队伍信息  如果过期时间小于当前时间 并且 过期时间非空  不展示
            if (new Date().after(team.getExpireTime()) && team.getExpireTime()!=null){
                continue;
            }
            // 拿到创建人的id
            Long userId = team.getUserId();
            if (userId == null) {
                continue;
            }
            User user = userService.getById(userId);
            TeamUserVO teamUserVO;
            try {
                // 脱敏队伍信息
                teamUserVO = new TeamUserVO();
                BeanUtils.copyProperties(teamUserVO, team);
                if (user!=null){
                    // 脱敏用户信息
                    UserVO userVO = new UserVO();
                    BeanUtils.copyProperties(userVO, user);
                    // 队伍添加创建用户信息
                    teamUserVO.setCreateUser(userVO);
                    // 添加队伍用户id
                    QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
                    userTeamQueryWrapper.eq("team_id",team.getId());
                    List<Long> longs = userTeamService.list(userTeamQueryWrapper).stream().map(item -> item.getUserId()).collect(Collectors.toList());
                    teamUserVO.setUserIds(longs);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            userVOList.add(teamUserVO);
        }
        return userVOList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class) // 指定返回错误类
    public boolean updateTeam(TeamUpdateRequest teamUpdateRequest, User userLogin) {
        if (teamUpdateRequest==null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long id = teamUpdateRequest.getId();
        if (id==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Team oldTeam = getById(id);
        if (oldTeam==null){
            throw new BusinessException(ErrorCode.NULL_ERROR,"队伍不存在");
        }
        // 是否为队伍创建者或者为管理员
        if (!Objects.equals(userLogin.getId(), oldTeam.getUserId()) && !userService.isAdmin(userLogin)){
            throw new BusinessException(ErrorCode.NO_AUTH,"无权限修改队伍");
        }
        // 如果队伍加密，则必须要有密码
        TeamStatusEnum teamStatusEnumByValue = TeamStatusEnum.getTeamStatusEnumByValue(teamUpdateRequest.getStatus());
        if (TeamStatusEnum.SECRET.equals(teamStatusEnumByValue) && StringUtils.isBlank(oldTeam.getPassword())){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"加密队伍必须要输入密码");
        }
        Team team = new Team();
        try {
            BeanUtils.copyProperties(team,teamUpdateRequest);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        // 修改队伍
        return updateById(team);
    }

    @Override
    @Transactional(rollbackFor = Exception.class) // 指定返回错误类
    public boolean joinTeam(TeamJoinRequest teamJoinRequest,User userLogin) {
        if (teamJoinRequest == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 队伍必须存在
        Long teamId = teamJoinRequest.getTeamId();
        if (teamId==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Team team = getById(teamId);
        if (team==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍不存在");
        }
        // 队伍不能过期
        Date expireTime = team.getExpireTime();
        if (expireTime!=null && new Date().after(expireTime)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍过期");
        }
        // 不能加入私有队伍
        Integer status = team.getStatus();
        TeamStatusEnum teamStatusEnumByValue = TeamStatusEnum.getTeamStatusEnumByValue(status);
        if (status!=null && TeamStatusEnum.PRIVATE.equals(teamStatusEnumByValue)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"不能加入私有的队伍");
        }
        // 密码必须正确
        String password = teamJoinRequest.getPassword();
        if (TeamStatusEnum.SECRET.equals(teamStatusEnumByValue)){
            if (StringUtils.isBlank(password) || !password.equals(team.getPassword())){
                throw new BusinessException(ErrorCode.NULL_ERROR,"密码错误");
            }
        }

        Long userId = userLogin.getId();

        // 用户加入的队伍不能大于五个
        QueryWrapper<UserTeam> teamQueryWrapper = new QueryWrapper<>();
        teamQueryWrapper.eq("user_id",userId);
        long hasJoinTeamsCount = userTeamService.count(teamQueryWrapper);
        if (hasJoinTeamsCount>5){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"最多加入(创建)五个队伍");
        }
        // 不能加入已经加入的队伍
        teamQueryWrapper = new QueryWrapper<>();
        teamQueryWrapper.eq("user_id",userId);
        teamQueryWrapper.eq("team_id",teamId);
        long hasUserJoinTeam = userTeamService.count(teamQueryWrapper);
        if (hasUserJoinTeam>0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"不能加入已经加入的队伍");
        }
        // 已加入队伍的的人数=队伍总人数 队伍已满
        teamQueryWrapper = new QueryWrapper<>();
        teamQueryWrapper.eq("team_id",teamId);
        long teamHasJoinCount = userTeamService.count(teamQueryWrapper);
        if (teamHasJoinCount>=team.getMaxNum()){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍已满");
        }
        // 新增队伍关联信息
        UserTeam userTeam = new UserTeam();
        userTeam.setUserId(userId);
        userTeam.setTeamId(teamId);
        userTeam.setJoinTime(new Date());
        return userTeamService.save(userTeam);
    }

    @Override
    @Transactional(rollbackFor = Exception.class) // 指定返回错误类
    public boolean exitTeam(long teamId, User loginUser) {
        if (teamId<=0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 获取信息
        Team team = getTeamById(teamId);
        Long userId = loginUser.getId();
        // 是否已经加入队伍
        isJoinTeam(teamId,userId);
        // 查看队伍人数
        long teamUserCount = getTeamUserCount(teamId);
        // 如果只剩一人，直接删除队伍
        if (teamUserCount == 1){
            removeById(teamId);
            // 移除用户和队伍关系
        }else {
            // 判断是否是队长 如果是队长则直接转移队长给第二个加入者
            if (Objects.equals(team.getUserId(), userId)){
                // 查询所有加入的人

                QueryWrapper<UserTeam> teamQueryWrapper = new QueryWrapper<>();
                teamQueryWrapper.eq("teamId",teamId);
                teamQueryWrapper.last("order by id asc limit 2");
                List<UserTeam> userTeamList = userTeamService.list(teamQueryWrapper);
                if (CollectionUtils.isEmpty(userTeamList) || userTeamList.size()<= 1){
                    throw new BusinessException(ErrorCode.SYS_ERROR,"查询队伍信息错误");
                }
                UserTeam userTeam = userTeamList.get(1);
                Long nextTeamLeaderId = userTeam.getUserId();
                // 更新队长
                Team updateTeam = new Team();
                updateTeam.setId(teamId);
                updateTeam.setUserId(nextTeamLeaderId);
                boolean result = updateById(updateTeam);
                if (!result){
                    throw new BusinessException(ErrorCode.SYS_ERROR,"更新队长失败");
                }
                // 移除用户和队伍关系
            }
        }
        // 移除用户和队伍关系
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("user_id",userId);
        userTeamQueryWrapper.eq("team_id",teamId);
        return userTeamService.remove(userTeamQueryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class) // 指定返回错误类
    public boolean deleteTeam(long teamId, User loginUser) {
        Team team = getTeamById(teamId);
        // 是否已经加入队伍
        Long userId = loginUser.getId();
        isJoinTeam(teamId, userId);
        // 不是队长无权限删除队伍
        if (!Objects.equals(team.getUserId(), userId)){
            throw new BusinessException(ErrorCode.NO_AUTH,"无权限删除队伍");
        }
        // 移除所有的关系
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("team_id",teamId);
        boolean result = userTeamService.remove(userTeamQueryWrapper);
        if (!result){
            throw new BusinessException(ErrorCode.SYS_ERROR,"删除队伍关联信息失败");
        }
        // 删除队伍
        return removeById(teamId);
    }

    /**
     * 查看队伍存在人数
     * @param teamId 队伍id
     * @return 队伍现人数
     */
    private long getTeamUserCount(long teamId){
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("team_id",teamId);
        return userTeamService.count();
    }

    /**
     * 获取队伍信息
     * @param teamId 队伍id
     * @return 队伍
     */
    private Team getTeamById(long teamId){
        if(teamId<=0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Team team = getById(teamId);
        // 队伍是是否存在
        if (team==null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍不存在");
        }
        return team;
    }


    /**
     * 是否加入队伍
     * @param teamId 队伍id
     * @param userId 用户id
     */
    private void isJoinTeam(Long teamId, Long userId) {
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("user_id",userId);
        userTeamQueryWrapper.eq("team_id",teamId);
        long TeamUserJoinCount = userTeamService.count(userTeamQueryWrapper);
        if (TeamUserJoinCount!=1){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"未加入队伍");
        }
    }

}




